package com.glacier.common.core.factory;


import com.glacier.common.core.domain.Treeable;

import java.util.*;

/**
 * date 2022-10-26 09:46
 * 树形数据工厂类
 *
 * @author glacier
 * @version 1.0
 */
public class TreeFactory {

    private TreeFactory() {
    }

    /**
     * 逐级向上找到所有父类（包含祖父、曾祖父等）
     *
     * @param <T>     树形类型
     * @param current 当前类
     * @param list    带选择父类的集合
     * @return
     */
    public static <T extends Treeable<T>> List<T> findParents(final T current, final List<T> list) {
        List<T> parents = new ArrayList<>(16);
        for (T t : list) {
            if (Objects.equals(t.getId(), current.getParentId())) {
                parents.add(t);
                parents.addAll(findParents(t, list));
            }
        }
        return parents;
    }

    /**
     * 将扁平化集合转为树形集合
     *
     * @param list 一般集合
     * @param <T>  树形类型
     * @return 树形集合
     */
    public static <T extends Treeable<T>> List<T> buildTree(final List<T> list) {
        List<T> tops = new ArrayList<>(list.size() + 1);
        List<T> others = new ArrayList<>(list.size() + 1);
        for (T t : list) {
            if (t.getParentId() == null || t.getParentId().isBlank()) {
                tops.add(t);
            } else {
                others.add(t);
            }
        }
        tops.forEach(e -> fillChildren(e, others));
        return tops;
    }


    /**
     * 找到父级下的所有子类，并赋值给父类的子类集合属性
     *
     * @param <T>
     * @param parent
     * @param list
     * @return
     */
    private static <T extends Treeable<T>> void fillChildren(final T parent, final List<T> list) {
        List<T> children = new ArrayList<>(list.size() + 1);
        List<T> others = new ArrayList<>(list.size() + 1);
        for (T t : list) {
            if (Objects.equals(parent.getId(), t.getParentId())) {
                children.add(t);
            } else {
                others.add(t);
            }
        }
        children.forEach(e -> fillChildren(e, others));
        // 排序
        children.sort(Comparator.comparingInt(Treeable::getSort));
        parent.setChildren(children);
    }
}
